package com.ruoyi.pv.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.doudou.core.date.DateUtil;
import com.doudou.core.lang.Option;
import com.doudou.core.throwable.GlobalException;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.pv.domain.PvAppoint;
import com.ruoyi.pv.domain.PvAppointTime;
import com.ruoyi.pv.domain.PvStudentRecord;
import com.ruoyi.pv.domain.vo.PvAppointRecordNumVo;
import com.ruoyi.pv.domain.vo.PvAppointRecordNumVo1;
import com.ruoyi.pv.domain.vo.PvAppointTimeDTO;
import com.ruoyi.pv.domain.vo.PvStudentRecordExcelVo;
import com.ruoyi.pv.service.IPvAppointService;
import com.ruoyi.pv.service.IPvStudentRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.pv.mapper.PvAppointRecordMapper;
import com.ruoyi.pv.domain.PvAppointRecord;
import com.ruoyi.pv.service.IPvAppointRecordService;

/**
 * 预约记录Service业务层处理
 *
 * @author zzx
 * @date 2023-04-22
 */
@Service
public class PvAppointRecordServiceImpl implements IPvAppointRecordService {
    private static final Log log = LogFactory.get(IPvAppointRecordService.class);

    @Autowired private PvAppointRecordMapper pvAppointRecordMapper;

    @Autowired private IPvAppointService pvAppointService;

    @Autowired private IPvStudentRecordService pvStudentRecordService;


    /**
     * 查询预约记录
     *
     * @param id 预约记录主键
     * @return 预约记录
     */
    @Override
    public PvAppointRecord selectPvAppointRecordById(Long id) {
        PvAppointRecord pvAppointRecord = pvAppointRecordMapper.selectPvAppointRecordById(id);
        return pvAppointRecord;
    }

    /**
     * 查询预约记录列表
     *
     * @param pvAppointRecord 预约记录
     * @return 预约记录
     */
    @Override
    public List<PvAppointRecord> selectPvAppointRecordList(PvAppointRecord pvAppointRecord) {
        return pvAppointRecordMapper.selectPvAppointRecordList(pvAppointRecord);
    }

    /**
     * 新增预约记录
     *
     * @param pvAppointRecord 预约记录
     * @return 结果
     */
    @Override
    public int insertPvAppointRecord(PvAppointRecord pvAppointRecord) {
        pvAppointRecord.setCreateTime(DateUtils.getNowDate());
        return pvAppointRecordMapper.insertPvAppointRecord(pvAppointRecord);
    }

    /**
     * 修改预约记录
     *
     * @param pvAppointRecord 预约记录
     * @return 结果
     */
    @Override
    public int updatePvAppointRecord(PvAppointRecord pvAppointRecord) {
        return pvAppointRecordMapper.updatePvAppointRecord(pvAppointRecord);
    }

    /**
     * 批量删除预约记录
     *
     * @param ids 需要删除的预约记录主键
     * @return 结果
     */
    @Override
    public int deletePvAppointRecordByIds(Long[] ids) {
        return pvAppointRecordMapper.deletePvAppointRecordByIds(ids);
    }

    /**
     * 删除预约记录信息
     *
     * @param id 预约记录主键
     * @return 结果
     */
    @Override
    public int deletePvAppointRecordById(Long id) {
        return pvAppointRecordMapper.deletePvAppointRecordById(id);
    }

    @Override
    public Map<Long,PvAppointRecordNumVo> selectPvAppointRecordCountByAppointAndDateGroupByTime(Long appointId, String date) {
        return pvAppointRecordMapper.selectPvAppointRecordCountByAppointAndDateGroupByTime(appointId,date);
    }

    private final static Lock LOCK = new ReentrantLock();
    /**
     * 预约
     */
    @Override
    public AjaxResult doAppoint(PvAppointRecord pvAppointRecord) {
        LOCK.lock();
        try{
            //先查询该用户是否以报名
            PvStudentRecord pvStudentRecord = pvStudentRecordService.selectPvStudentRecordThisYear(pvAppointRecord.getStuId());
            if (ObjectUtil.isEmpty(pvStudentRecord)){
                return AjaxResult.error("未查询到今年的报名记录，请前往主页报名");
            }
            //查询是否有重复的预约记录
            List<PvAppointRecord> pvAppointRecords = selectPvAppointRecordList(
                    PvAppointRecord.builder().stuId(pvAppointRecord.getStuId()).appointId(pvAppointRecord.getAppointId()).build());
            if (ObjectUtil.isNotEmpty(pvAppointRecords)){
                return AjaxResult.error("已有重复的预约记录，请勿重复预约");
            }
            //判断容量是否足够
            checkQuantityIsEnough(pvAppointRecord.getAppointId(),pvAppointRecord.getAppointDate(),pvAppointRecord.getAppointTimeId());
            pvAppointRecord.setStatus(1);//直接通过
            insertPvAppointRecord(pvAppointRecord);
        }catch (Exception e){
            log.info(e);
            return AjaxResult.error(e.getMessage());
        }finally {
            LOCK.unlock();
        }
        return AjaxResult.success();
    }

    /**
     * 查询报名班未预约的学员
     * @param appointId 预约编号
     * @param deptId 机构
     */
    @Override
    public List<Map<String, String>> selectNotAppointList(Long appointId, Long deptId) {
        return pvAppointRecordMapper.selectNotAppointList(appointId,deptId);
    }

    @Override
    public PvAppointTimeDTO getAppointRecordTimeListByAppointId(Long appointId ,Long id) {
        PvAppointTimeDTO pvAppointTimeDTO = new PvAppointTimeDTO();

        PvAppointRecord pvAppointRecord = pvAppointRecordMapper.selectPvAppointRecordById(id);
        pvAppointTimeDTO.setPvAppointRecord(pvAppointRecord);
        // 查询预约对象信息
        PvAppoint appoint = pvAppointRecordMapper.selectPvAppointList(appointId);
        if (appoint == null) {
            pvAppointTimeDTO.setAppoint(new PvAppoint());
            pvAppointTimeDTO.setFilteredList(new ArrayList<>());
            return pvAppointTimeDTO;
        }

        pvAppointTimeDTO.setAppoint(appoint);

        // 查询可预约时间段
        List<PvAppointTime> list = pvAppointRecordMapper.getAppointTimeListByAppointId(appointId);
        if (list == null || list.isEmpty()) {
            pvAppointTimeDTO.setFilteredList(new ArrayList<>());
            return pvAppointTimeDTO;
        }

        // 查询各时间段已预约数量
        List<PvAppointRecordNumVo> pvAppointRecordNumVos = pvAppointRecordMapper.selectPvAppointRecordCountByAppointId(appointId);

        // 将已预约数量转为Map便于查找
        Map<Long, Integer> recordNumMap = (pvAppointRecordNumVos != null ? pvAppointRecordNumVos : new ArrayList<PvAppointRecordNumVo>())
                .stream()
                .collect(Collectors.toMap(
                        PvAppointRecordNumVo::getAppointTimeId,
                        PvAppointRecordNumVo::getNum,
                        (existing, replacement) -> existing
                ));

        // 计算剩余可预约数量并过滤掉小于等于0的记录
        List<PvAppointTime> filteredList = list.stream()
                .peek(pvAppointTime -> {
                    int usedNum = recordNumMap.getOrDefault(pvAppointTime.getId(), 0);
                    pvAppointTime.setNum(appoint.getQuantity() - usedNum);
                })
                .filter(pvAppointTime -> pvAppointTime.getNum() > 0)
                .collect(Collectors.toList());

        pvAppointTimeDTO.setFilteredList(filteredList);
        return pvAppointTimeDTO;
    }


    /**
     * 判断容量是否足够
     */
    public void checkQuantityIsEnough(Long appointId, Date appointDate, Long appointTimeId) {
        PvAppoint appoint = pvAppointService.selectPvAppointById(appointId);
        //获取已经预约人数
        Map<Long, PvAppointRecordNumVo> recordNumVos = selectPvAppointRecordCountByAppointAndDateGroupByTime(appointId, DateUtil.format(appointDate,"yyyy-MM-dd"));
        Option<PvAppointRecordNumVo> numOptional = Option.of(recordNumVos.get(appointTimeId));
        if (numOptional.get(PvAppointRecordNumVo.builder().num(0).build()).getNum() >= appoint.getQuantity()){
            throw new GlobalException("该时段容量不足，请选择其他时间段");
        }
    }
}
